#pragma once
#include <iostream>
#include <pthread.h>
#include <vector>
#include <queue>
#include <memory>
namespace mythpool
{
    static const int defaultcap = 10;

    template <class T>
    class ThPool
    {
        class thinfo
        {
        public:
            pthread_t _tid;
            std::string _name;
        };
        void Lock()
        {
            pthread_mutex_lock(&_tp_lock);
        }
        void Unlock()
        {
            pthread_mutex_unlock(&_tp_lock);
        }
        void pushwait()
        {
            pthread_cond_wait(&_tp_wait,&_tp_lock);
        }
        void popwait()
        {
            pthread_cond_signal(&_tp_wait);
        }
        static void *dealtask(void *args)
        {
            ThPool<T> * tp = static_cast<ThPool<T> *>(args);
            const std::string& name = tp->getname(pthread_self());
            while(true)
            {
                tp->Lock();
                if(tp->_task.empty())
                {
                    tp->pushwait();
                }
                T t = tp->pop();
                tp->Unlock();
                
                t();
            }
        }
        T pop()
        {
            T t = _task.front();
            _task.pop();
            return t;
        }
    public:
        const std::string getname(const pthread_t& tid)
        {
            for(auto& tp : _tp)
            {
                if(tp._tid == tid)
                    return tp._name;
            }
            return "";
        }
        void inittp()
        {
            int maxcap = _tp.size();
            for(int i = 0;i < maxcap;i++)
            {
                _tp[i]._name = "thread :" + std::to_string(i);
                pthread_create(&(_tp[i]._tid),nullptr,dealtask,this);

            }
        }

        void push(const T& t)
        {
            Lock();
            _task.push(t);
            popwait();
            Unlock();
        }

        static ThPool<T> * GetOnceCase()
        {
            if(nullptr == TP)
            {
                pthread_mutex_lock(&lock);
                if(nullptr == TP)
                {
                    TP = new ThPool<T>();
                }
            }
            return TP;
        }

    private:
        ThPool(int maxcap = defaultcap)
            :_tp(maxcap)
        {
            pthread_cond_init(&_tp_wait,nullptr);
            pthread_mutex_init(&_tp_lock,nullptr);
        }
        ~ThPool()
        {
            pthread_mutex_destroy(&_tp_lock);
            pthread_cond_destroy(&_tp_wait);
        }
        ThPool(const ThPool<T>& tp) = delete;
        ThPool<T>& operator=(const ThPool<T>& tp) = delete;
    private:
        std::vector<thinfo> _tp;
        std::queue<T> _task;

        pthread_mutex_t _tp_lock;
        pthread_cond_t _tp_wait;

        static ThPool<T> *TP;
        static pthread_mutex_t lock;

    };
    template <class T>
    ThPool<T> * ThPool<T>::TP = nullptr;
    template <class T>
    pthread_mutex_t ThPool<T>::lock = PTHREAD_MUTEX_INITIALIZER;

}